package com.vip.mvc.netty;

import com.vip.mvc.dispacher.MyDispacher;
import com.vip.mvc.utils.JSONUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMessage;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * Json格式的handler
 * Created by cloudy.xie on 17/1/19.
 */
public class NettyHttpJsonDispatchHandler extends ChannelInboundHandlerAdapter {

    private static Logger log = LoggerFactory.getLogger(NettyHttpJsonDispatchHandler.class);
    private volatile NettyHttpRequestParam httpParam = new NettyHttpRequestParam();
    private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //Disk

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object requestMsg) throws Exception {
        //get request
        NettyHttpRequestParam requestParam = readHttpRequest(ctx, requestMsg);

        if (requestParam.isValidRequest()) {
            //dispatcher
            MyDispacher.getInstance().doDispatch(ctx,requestParam);
            //send response
//            writeHttpResponse(ctx, responseObj);
        }
    }


    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    private NettyHttpRequestParam readHttpRequest(ChannelHandlerContext ctx, Object requestMsg) {
        try {
            if ((requestMsg instanceof HttpMessage) && HttpHeaders.is100ContinueExpected((HttpMessage) requestMsg)) {
                ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE));
            }

            readHttpUrl(httpParam, requestMsg);
            readHttpContent(httpParam, requestMsg);
        } catch (Exception e) {
            log.error("readHttpRequest-error", e);
        } finally {
            ReferenceCountUtil.release(requestMsg);
        }
        return httpParam;
    }

    private void readHttpUrl(NettyHttpRequestParam httpParam, Object requestMsg) {
        if (requestMsg instanceof HttpRequest) {
            log.debug("[channelRead: HTTP-REQUEST]");
            HttpRequest httpRequest = (HttpRequest) requestMsg;
            httpParam.setHttpMethod(httpRequest.getMethod());

            if(httpRequest.getUri().contains("?")) {
                String[] uriArr = httpRequest.getUri().split("\\?");
                httpParam.setUrl(uriArr[0]);
                httpParam.setReqParam(uriArr[1]);
            }else{
                httpParam.setUrl(httpRequest.getUri());
            }

            if(httpRequest.getMethod().equals(HttpMethod.POST)
                    || httpRequest.getMethod().equals(HttpMethod.PUT)
                    || httpRequest.getMethod().equals(HttpMethod.PATCH)
                    || httpRequest.getMethod().equals(HttpMethod.DELETE)) {
                HttpPostRequestDecoder decoder  = new HttpPostRequestDecoder(factory, httpRequest);
                decoder.isMultipart();
            }

            HttpHeaders headers = httpRequest.headers();
            if (!headers.isEmpty()) {
                for (Map.Entry<String, String> header : headers) {
                    if (Objects.equals(header.getKey(), "Host")) {
                        httpParam.setHost(header.getValue());
                    } else if (Objects.equals(header.getKey(), "Content-Type")) {
                        httpParam.setContentType(header.getValue());
                    }
                }
            }

        }
    }

    private void readHttpContent(NettyHttpRequestParam httpParam, Object requestMsg) throws IOException {
        StringBuilder sb = new StringBuilder();
        if (requestMsg instanceof HttpContent) {
            ByteBuf _body = PooledByteBufAllocator.DEFAULT.buffer();
            HttpContent content = (HttpContent) requestMsg;
            ByteBuf thisContent = content.content();
            if (thisContent.isReadable()) {
                _body.writeBytes(thisContent);
                sb.append(_body.toString(CharsetUtil.UTF_8));
            }

            String bodyStr = sb.toString();
            if (StringUtils.isNotBlank(bodyStr) && bodyStr.contains("form-data")) {
                bodyStr = bodyStr.replaceAll("\"", "").replaceAll("\r\n\r\n", ",").replaceAll("\r\n", "");
                String[] bodyArr = bodyStr.split("------WebKitForm");

                Map<String, String> map = new HashMap<>();
                for (String bodyValue : bodyArr) {
                    if (StringUtils.isBlank(bodyValue)) continue;
                    if (!bodyValue.contains("form-data")) continue;
                    String paramStr = bodyValue.substring(bodyValue.indexOf("name=") + 5);
                    String[] paramArr = paramStr.split(",");
                    map.put(paramArr[0], paramArr[1]);
                }
                bodyStr = JSONUtils.toJSON(map);

            }

            httpParam.setReqBody(bodyStr==null ?"":bodyStr);
        }
    }

//    private void writeHttpResponse(ChannelHandlerContext ctx, Object responseObj) throws Exception {
//        String respJson = JSONUtils.toJSON(responseObj);
//        writeHttpResponse(ctx, Unpooled.copiedBuffer(respJson, CharsetUtil.UTF_8));
//    }
//
//    private void writeHttpResponse(ChannelHandlerContext ctx, ByteBuf content) {
//        if (ctx.channel().isWritable()) {
//            FullHttpResponse msg;
//            if (content != null) {
//                msg = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
//                msg.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain;charset=UTF-8");
//            } else {
//                msg = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
//            }
//
//            if (msg.content() != null)
//                msg.headers().set(HttpHeaders.Names.CONTENT_LENGTH, msg.content().readableBytes());
//
//            // not keep-alive
//            ctx.write(msg).addListener(ChannelFutureListener.CLOSE);
//        }
//    }
}
